xlv.obj.inputMask={
	extend:function(){
		this.extend('xlv.obj.input');
	},
	implement:function(){
	},
	create:function(tag){
		var div=document.createElement((tag||'div'));
		div.setAttribute('xlvobject','xlv.obj.inputMask');
		return div;			
	},
	pub:{
		mask:{
			inputFilter:/^[A-Za-z0-9\u00A0]/,
			valid_9:/^[0-9]+/,
			valid_a:/^[A-Za-z]+/,
			valid_A:/^[A-Za-z]+/,
			valid_x:/^[A-Za-z0-9\u00A0]/
		}
	},
	properties:{
		dmName:null,
		dmPath:null,
		validateRegExp:null,
		maskEmptyChr: '_',
		mask:''
	},
	method:{
		initial:function(){
			this.$super('xlv.obj.input.initial');
			this.$V.editor.readOnly=true;
			this.$V.pseudoCursorPosition=0;
			if(!this.$P.dmName)	this.editor_valueToEditor('');
		},
		_mouseup:function(event){
			var p = this._getSelectionStart();
			this._setSelection(p);
		},
		_click:function(event){
			event.stop();
			if(!this.editor_editing())	this._editor_startEdit();
		},
		_mask_keydown:function(event) {
			var code=(event.keyCode||event.which);
			if(code==this.editor_properties.commitKeyCode||code==this.editor_properties.cancelKeyCode) return;
			event.stop();
			switch(code) {
				case 8: // Backspace
					var p = this._getSelectionStart();
					this._updSelection(p, this.$P.maskEmptyChr.charCodeAt(0));
					this._selectPrevious();
					return;
				case 36: // Home
					this._selectFirst();
					return;
				case 35: // End
					this._selectLast();
					return;
				case 37: // Left
				case 38: // Up
					this._selectPrevious();
					return;
				case 39: // Right
				case 40: // Down
					this._selectNext();
					return;
				case 46: // Delete
					var p = this._getSelectionStart();
					this._updSelection(p, this.$P.maskEmptyChr.charCodeAt(0));
					return;
			}
			var p = this._getSelectionStart();
			this._setSelection(p);
			if(this.isValidInput(p,code)){
				if(this.$P.mask.charAt(p)=='a') code=String.fromCharCode(code).toLowerCase().charCodeAt(0);
				if(this.$P.mask.charAt(p)=='A') code=String.fromCharCode(code).toUpperCase().charCodeAt(0);
				if(this.$P.mask.charAt(p)=='x' && event.shiftKey) code=String.fromCharCode(code).toUpperCase().charCodeAt(0);
				if(this.$P.mask.charAt(p)=='x' && !event.shiftKey) code=String.fromCharCode(code).toLowerCase().charCodeAt(0);
				this._updSelection(p,code);
				this._selectNext(p);
			}
		},
		_selectFirst:function(){
			this._setSelection(this._nextInputPosition(-1));
		},
		_selectLast:function(){
			this._setSelection(this._prevInputPosition(this.$P.mask.length));
		},
		_selectPrevious: function(p) {
			p=(p==undefined)?this._getSelectionStart():p;
			this._setSelection(this._prevInputPosition(p));
		},
		_selectNext: function(p) {
			p=(p==undefined)?this._getSelectionStart():p;
			this._setSelection(this._nextInputPosition(p));
		},
		_setSelection:function(p) {
			var editor=this.$V.editor;
			if(editor.setSelectionRange)	{
				editor.setSelectionRange(p,p+1);
				this.$V.pseudoCursorPosition=p;
			}else if(editor.createTextRange) {
				var r = editor.createTextRange();
				r.collapse();
				r.moveStart("character",p);
				r.moveEnd("character",1);
				r.select();
			}
		},
		_updSelection: function(p,keycode) {
			var editor=this.$V.editor;
			var value = editor.value;
			var output='';
			output += value.substring(0, p);
			output += String.fromCharCode(keycode);
			output += value.substr(p+1);
			editor.value = output;
			if(Element.hasClassName(this.$V.editor,'validate_error'))this._validateMask();
			this._setSelection(p);
		},
		_getSelectionStart:function() {
			var editor=this.$V.editor;
			var p = 0;
			if(editor['selectionStart'])	{
				p=editor.selectionStart;
			}else if(document.selection) {
				var r = document.selection.createRange().duplicate();
				r.moveEnd('character',editor.value.length);
				p = (r.text=='') ? 0:editor.value.lastIndexOf(r.text);
			}else{
				p=this.$V.pseudoCursorPosition;
			}
			var first=this._nextInputPosition(-1);
			if(p<first)p=first;
			var end=this._prevInputPosition(this.$P.mask.length);
			if(p>end)p=end;
			return p;
		},
		_nextInputPosition:function(p){
			for(var i=p+1,len=this.$P.mask.length;i<len; i++)
				if(this._isInputPosition(i)) return i;
			return p;
		},
		_prevInputPosition:function(p){
			for(var i=p-1; i>=0; i--)if(this._isInputPosition(i)) return i;
			return p;
		},
		_isInputPosition:function(p) {
			if(p<0||p>=this.$P.mask.length)return false;
			return ("9aAx".indexOf(this.$P.mask.toLowerCase().charAt(p)) >= 0);
		},
		isValidInput:function(p,keycode) {
			var ax9 = this.$P.mask.toLowerCase().charAt(p);
			var chr=String.fromCharCode(keycode).toLowerCase();
			if(!xlv.obj.inputMask.pub.mask.inputFilter.test(chr))return false;
			switch(ax9) {
				case '9':
					if(xlv.obj.inputMask.pub.mask.valid_9.test(chr)) return true;
					break;
				case 'a':
					if(xlv.obj.inputMask.pub.mask.valid_a.test(chr)) return true;
					break;
				case 'A':
					if(xlv.obj.inputMask.pub.mask.valid_a.test(chr)) return true;
					break;
				case 'x':
					if(xlv.obj.inputMask.pub.mask.valid_x.test(chr)) return true;
					break;
				default:
					return false;
			}
			return false;
		},
		_wearMask:function(value) {
			var mask = this.$P.mask.toLowerCase();
			var output = '';
			for(var i = 0,u = 0,len = mask.length; i < len; i++) {
				var mask_chr=mask.charAt(i);
				switch(mask_chr) {
					case '9': case 'a': case 'A': case 'x':
						output += (u<value.length)?value.charAt(u++):this.$P.maskEmptyChr;
						break;
					default:
						output += mask_chr;
						break;
				}
			}
			return output;
		},
		_validateMask:function(){
			var mask = this.$P.mask.toLowerCase();
			var value=this.$V.editor.value;
			Element.removeClassName(this.$V.editor,'validate_error');
			for(var i = 0,u = 0,len = mask.length; i < len; i++) {
				var mask_chr=mask.charAt(i);
				var chr=value.charAt(i);
				switch(mask_chr) {
					case '9': 
						if(chr != this.$P.maskEmptyChr && !xlv.obj.inputMask.pub.mask.valid_9.test(chr)){
							Element.addClassName(this.$V.editor,'validate_error');
							return;
						}
						break;
					case 'a': 
						if(chr != this.$P.maskEmptyChr && !xlv.obj.inputMask.pub.mask.valid_a.test(chr)){
							Element.addClassName(this.$V.editor,'validate_error');
							return;
						}
						break;
					case 'A': 
						if(chr != this.$P.maskEmptyChr && !xlv.obj.inputMask.pub.mask.valid_A.test(chr)){
							Element.addClassName(this.$V.editor,'validate_error');
							return;
						}
						break;
					case 'x':
						if(chr != this.$P.maskEmptyChr && !xlv.obj.inputMask.pub.mask.valid_x.test(chr)){
							Element.addClassName(this.$V.editor,'validate_error');
							return;
						}
						break;
				}
			}
		},
		_stripMask:function() {
			var value = this.$V.editor.value;
			var output = '';
			for(var i = 0,len=value.length; i < len; i++) {
				if(this._isInputPosition(i)){
					if(value.charAt(i)!=this.$P.maskEmptyChr)
						 output+=value.charAt(i);
					else output+=' ';
				}
			}
			output=output.replace(/\s+$/, '');
			return output;
		},
		valueWithMask:function(){
			return this.$V.editor.value.replace(new RegExp(''+this.$P.maskEmptyChr,'g'),' ');
		},
		editor_valueToEditor:function(value){
			this.$V.editor.value=this._wearMask(value);
			this._validateMask();
		},
		editor_valueFromEditor:function(){
			return this._stripMask();
		},
		editor_startEdit:function(){
			this.$super('xlv.obj.input.editor_startEdit');
			this.addEventHandler('mouseup','_mouseup',this.$V.editor);
			this.addEventHandler('keydown','_mask_keydown',this.$V.editor);
			this._selectFirst();
		},
		editor_endEdit:function(commit){
			this.$super('xlv.obj.input.editor_endEdit',commit);
			this.removeObserve('mouseup','_mouseup',this.$V.editor);
			this.removeObserve('keydown','_mask_keydown',this.$V.editor);
		}
	}
};
